package com.nvwa.coding.util.num;

import com.fasterxml.jackson.annotation.JsonCreator;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 表示浮点数范围的实现
 *
 * @author wangjing
 * @since 1.0
 */
public class DoubleRange extends AbstractRange<Double> {
    private static final DoubleRange UNBOUNDED = DoubleRange.of(Bound.unbounded(), Bound.unbounded());

    private DoubleRange(Bound<Double> lowerBound, Bound<Double> upperBound) {
        super(lowerBound, upperBound);
    }

    /**
     * 返回当前范围和另一个范围覆盖的最大范围
     *
     * @param other 要计算的另一个范围，不能为null
     * @return 当前范围和另一个范围覆盖的最大范围
     * @throws NullPointerException 如果入参other为null
     */
    public DoubleRange unionMaxRange(DoubleRange other) {
        Bound<Double> lowerBound = this.getLowerBound().lowerUnion(other.getLowerBound());
        Bound<Double> upperBound = this.getUpperBound().upperUnion(other.getUpperBound());

        return DoubleRange.of(lowerBound, upperBound);
    }

    /**
     * 返回一个无界的 {@link DoubleRange}
     *
     * @return 一个无界的 {@link DoubleRange}
     */
    public static DoubleRange unbounded() {
        return UNBOUNDED;
    }

    /**
     * 创建一个包含边界的 {@link DoubleRange}
     *
     * @param from 下限值
     * @param to   上限值
     * @return 由上下限值组成的包含边界的 {@link DoubleRange}
     */
    public static DoubleRange closed(Double from, Double to) {
        return new DoubleRange(Bound.inclusive(from), Bound.inclusive(to));
    }

    /**
     * 创建一个不包含边界的 {@link DoubleRange}
     *
     * @param from 下限值
     * @param to   上限值
     * @return 由上下限值组成的不包含边界的 {@link DoubleRange}
     */
    public static DoubleRange open(Double from, Double to) {
        return new DoubleRange(Bound.exclusive(from), Bound.exclusive(to));
    }

    /**
     * 创建一个不包含左边界但包含右边界的 {@link DoubleRange}
     *
     * @param from 下限值
     * @param to   上限值
     * @return 由上下限值组成不包含左边界但包含右边界的 {@link DoubleRange}
     */
    public static DoubleRange leftOpen(Double from, Double to) {
        return new DoubleRange(Bound.exclusive(from), Bound.inclusive(to));
    }

    /**
     * 创建一个包含左边界但不包含右边界的 {@link DoubleRange}
     *
     * @param from 下限值
     * @param to   上限值
     * @return 由上下限值组成包含左边界但不包含右边界的 {@link DoubleRange}
     */
    public static DoubleRange rightOpen(Double from, Double to) {
        return new DoubleRange(Bound.inclusive(from), Bound.exclusive(to));
    }

    /**
     * 使用给定的下限和上限创建一个 {@link DoubleRange}
     *
     * @param lowerBound 下限，不能为 {@code null}
     * @param upperBound 下限，不能为 {@code null}
     * @return 由给定的下限和上限创建的 {@link DoubleRange}
     */
    public static DoubleRange of(Bound<Double> lowerBound, Bound<Double> upperBound) {
        return new DoubleRange(lowerBound, upperBound);
    }

    /**
     * 创建一个仅包含指定值的 {@link DoubleRange}
     *
     * @param value {@link DoubleRange} 包含的唯一值
     * @return 一个仅包含指定值的 {@link DoubleRange}
     */
    public static DoubleRange just(Double value) {
        return DoubleRange.closed(value, value);
    }


    @JsonCreator
    @SuppressWarnings("unchecked")
    public static DoubleRange fromString(String rangeStr) {
        if (rangeStr == null || rangeStr.trim().isEmpty()) {
            return null;
        }
        List<Bound<Double>> bounds = Arrays.stream(rangeStr.split(","))
                .map(boundStr -> {
                    if ("(-∞".equals(boundStr) || "∞)".equals(boundStr)) {
                        return (Bound<Double>) Bound.unbounded();
                    }
                    boolean isBounded = true;
                    if (boundStr.startsWith("[")) {
                        boundStr = boundStr.substring(1);
                    } else if (boundStr.startsWith("(")) {
                        isBounded = false;
                        boundStr = boundStr.substring(1);
                    } else if (boundStr.endsWith("]")) {
                        boundStr = boundStr.substring(0, boundStr.length() - 1);
                    } else if (boundStr.endsWith(")")) {
                        isBounded = false;
                        boundStr = boundStr.substring(0, boundStr.length() - 1);
                    } else {
                        return null;
                    }
                    try {
                        Double value = Double.parseDouble(boundStr);
                        if (isBounded) {
                            return Bound.inclusive(value);
                        }
                        return Bound.exclusive(value);
                    } catch (NumberFormatException e) {
                        return null;
                    }
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        if (bounds.size() != 2) {
            throw new IllegalArgumentException("range 格式错误：" + rangeStr);
        }
        return new DoubleRange(bounds.get(0), bounds.get(1));
    }
}
